package cn.yto.print.service;

import cn.hutool.json.JSONUtil;
import cn.yto.print.listener.SerialPorListener;
import cn.yto.print.model.dto.SerialPortDTO;
import cn.yto.print.model.response.WeightResponse;
import cn.yto.print.socket.WeightSocketEndpoint;
import com.fazecast.jSerialComm.SerialPort;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.function.BiConsumer;

@Slf4j
@Service
public class SerialPortWeightService {

    // 串口对象引用
    private SerialPort serialPort;

    @Autowired
    private WeightSocketEndpoint weightSocketEndpoint;

    public void readWeight(String serialPortName, int baudRate, BiConsumer<String, SerialPortDTO> onDataReceived) {
        SerialPortDTO portInfo = new SerialPortDTO();
        serialPort = prepareSerialPort(serialPortName, baudRate);
        // 打开串口连接
        if (tryOpenSerialPort(serialPort, portInfo)) {
            onDataReceived.accept(formatWeight(0d), portInfo);
            registerSerialDataListener(portInfo, onDataReceived);
            log.info("连接 {} 串口成功, 开始读取设备数据 ...", serialPort.getSystemPortName());
        } else {
            log.info("连接 {} 串口失败", serialPort.getSystemPortName());
            throw new RuntimeException("连接串口失败");
        }
    }

    private SerialPort prepareSerialPort(String name, int baud) {
        SerialPort port = SerialPort.getCommPort(name);
        // 配置串口参数：8位数据位、1个停止位、无校验
        port.setComPortParameters(baud, 8, SerialPort.ONE_STOP_BIT, SerialPort.NO_PARITY);
        return port;
    }

    /**
     * 尝试打开串口，并填充串口信息
     */
    private boolean tryOpenSerialPort(SerialPort port, SerialPortDTO portInfo) {
        if (port.openPort()) {
            String sysName = port.getSystemPortName();
            String displayName = StringUtils.isEmpty(sysName) ? port.getDescriptivePortName() : sysName;
            portInfo.setSerialPortName(displayName);
            portInfo.setSerialBaudRate(String.valueOf(port.getBaudRate()));
            return true;
        }
        return false;
    }

    private void registerSerialDataListener(SerialPortDTO portInfo, BiConsumer<String, SerialPortDTO> onDataReceived) {
        SerialPorListener listener = new SerialPorListener(this.serialPort, (data) -> {
            WeightResponse resp = new WeightResponse(1, data);
            weightSocketEndpoint.massMessage(JSONUtil.toJsonStr(resp));
            onDataReceived.accept(formatWeight(data), portInfo);
        });
        serialPort.addDataListener(listener);
    }

    /**
     * 格式化重量数据为两位小数
     */
    private String formatWeight(double weight) {
        return String.format("%.2f", weight);
    }

    public void closeSerialPort() {
        if (serialPort != null && serialPort.isOpen()) {
            try {
                log.info("关闭 {} 串口连接, 停止读取设备数据", serialPort.getSystemPortName());
                serialPort.closePort();
            } catch (Exception e) {
                log.error("关闭串口称重连接异常", e);
            } finally {
                serialPort = null;
            }
        }
    }

}
